#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <random>
#include <vector>
#include <deque>
#include <atomic>
#include <map>

using namespace std::chrono_literals;

struct Packet_SW {
    int seqNum;
    std::string data;
};

struct Ack_SW {
    int ackNum;
};

const int WINDOW_SIZE = 4;
const int MAX_SEQ_NUM = 16;
const double PACKET_LOSS_PROB_SW = 0.15;
const double ACK_LOSS_PROB_SW = 0.1;
const auto TIMEOUT_DURATION_SW = 200ms;
const int TOTAL_PACKETS_TO_SEND = 20;


std::deque<Packet_SW> channel_A_to_B_SW;
std::deque<Ack_SW> channel_B_to_A_SW;
std::mutex channel_mutex_SW;
std::condition_variable cv_sender_SW;
std::condition_variable cv_receiver_SW;


std::atomic<int> sender_base(0);
std::atomic<int> sender_next_seq_num(0);
std::map<int, Packet_SW> sender_buffer;
std::atomic<bool> timer_running(false);
std::chrono::steady_clock::time_point timer_start_time;
std::mutex sender_mutex;

std::atomic<int> receiver_expected_seq_num(0);
std::mutex receiver_mutex;

std::atomic<bool> stop_simulation_SW(false);

std::default_random_engine generator_SW(std::chrono::system_clock::now().time_since_epoch().count());
std::uniform_real_distribution<double> distribution_SW(0.0, 1.0);


bool is_in_window(int seq, int base, int win_size) {
    int end = (base + win_size) % MAX_SEQ_NUM;
    if (base < end) {
        return seq >= base && seq < end;
    } else {
        return seq >= base || seq < end;
    }
}

void sender_SW() {
    int packets_sent_total = 0;

    while (sender_base < TOTAL_PACKETS_TO_SEND && !stop_simulation_SW) {

        {
            std::unique_lock<std::mutex> lock(sender_mutex);

            while (is_in_window(sender_next_seq_num, sender_base, WINDOW_SIZE) && sender_next_seq_num < TOTAL_PACKETS_TO_SEND) {
                 Packet_SW packet;
                 packet.seqNum = sender_next_seq_num;
                 packet.data = "Packet " + std::to_string(sender_next_seq_num);
                 sender_buffer[sender_next_seq_num] = packet;

                 std::cout << "[Sender] Sending " << packet.data << " with seq=" << packet.seqNum << std::endl;
                 {
                    std::lock_guard<std::mutex> chan_lock(channel_mutex_SW);
                     if (distribution_SW(generator_SW) >= PACKET_LOSS_PROB_SW) {
                         channel_A_to_B_SW.push_back(packet);
                     } else {
                          std::cout << "[Network] >>> Packet " << packet.seqNum << " lost A->B <<<" << std::endl;
                     }
                 }
                cv_receiver_SW.notify_one();


                 if (sender_base == sender_next_seq_num) {
                     timer_start_time = std::chrono::steady_clock::now();
                     timer_running = true;
                 }
                 sender_next_seq_num = (sender_next_seq_num + 1);

            }


            if (timer_running && (std::chrono::steady_clock::now() > timer_start_time + TIMEOUT_DURATION_SW)) {
                 std::cout << "[Sender] Timeout! Resending packets from seq=" << sender_base << std::endl;
                 timer_start_time = std::chrono::steady_clock::now();

                 int current_seq = sender_base;
                 while (current_seq != sender_next_seq_num) {
                     if(sender_buffer.count(current_seq)){
                         Packet_SW resend_packet = sender_buffer[current_seq];
                         std::cout << "[Sender] Resending " << resend_packet.data << " seq=" << resend_packet.seqNum << std::endl;
                         {
                             std::lock_guard<std::mutex> chan_lock(channel_mutex_SW);
                             if (distribution_SW(generator_SW) >= PACKET_LOSS_PROB_SW) {
                                 channel_A_to_B_SW.push_back(resend_packet);
                             } else {
                                  std::cout << "[Network] >>> Resent Packet " << resend_packet.seqNum << " lost A->B <<<" << std::endl;
                             }
                         }
                         cv_receiver_SW.notify_one();
                     }
                      current_seq = (current_seq + 1) % MAX_SEQ_NUM;
                      if (current_seq == 0 && sender_next_seq_num == 0) break; // Avoid infinite loop if next=0
                      if (sender_base > sender_next_seq_num && current_seq == sender_next_seq_num) break; // Handle wrap around

                 }
             }


             Ack_SW received_ack;
             bool ack_available = false;
             {
                 std::lock_guard<std::mutex> chan_lock(channel_mutex_SW);
                 if (!channel_B_to_A_SW.empty()) {
                     received_ack = channel_B_to_A_SW.front();
                     channel_B_to_A_SW.pop_front();
                     ack_available = true;
                 }
             }

            if (ack_available) {
                 std::cout << "[Sender] Received ACK " << received_ack.ackNum << std::endl;
                 int acked_seq = received_ack.ackNum;


                int new_base = (acked_seq + 1);
                 if (sender_base <= acked_seq || (sender_base > acked_seq + WINDOW_SIZE)) { // handle wrap around check carefully

                    while(sender_base != new_base){
                         sender_buffer.erase(sender_base);
                         sender_base = (sender_base + 1);
                         if (sender_base >= TOTAL_PACKETS_TO_SEND) break;
                    }


                     if (sender_base == sender_next_seq_num) {
                         timer_running = false;
                          std::cout << "[Sender] Timer stopped." << std::endl;
                     } else {
                         timer_start_time = std::chrono::steady_clock::now();
                         timer_running = true;
                           std::cout << "[Sender] Timer restarted for base=" << sender_base << std::endl;
                     }
                 } else {
                      std::cout << "[Sender] Received old/duplicate ACK " << acked_seq << ". Ignoring." << std::endl;
                 }

            }
        }
         std::this_thread::sleep_for(10ms);
    }

     std::cout << "[Sender] Finished sending all packets." << std::endl;
     stop_simulation_SW = true;
     cv_receiver_SW.notify_one();
     cv_sender_SW.notify_one();

}

void receiver_SW() {
     while (!stop_simulation_SW) {
         Packet_SW received_packet;
         bool packet_available = false;
         {
             std::unique_lock<std::mutex> lock(channel_mutex_SW);
             cv_receiver_SW.wait(lock, [&]{ return !channel_A_to_B_SW.empty() || stop_simulation_SW; });

            if (stop_simulation_SW && channel_A_to_B_SW.empty()) break;

            if(!channel_A_to_B_SW.empty()){
                 received_packet = channel_A_to_B_SW.front();
                 channel_A_to_B_SW.pop_front();
                 packet_available = true;
            }
         }

        if (packet_available) {
             std::cout << "[Receiver] Received packet with seq=" << received_packet.seqNum << std::endl;

            if (received_packet.seqNum == receiver_expected_seq_num) {
                 std::cout << "[Receiver] Packet seq=" << receiver_expected_seq_num << " is expected. Delivering data: " << received_packet.data << std::endl;

                 Ack_SW ack;
                 ack.ackNum = receiver_expected_seq_num;

                 {
                     std::lock_guard<std::mutex> lock(channel_mutex_SW);
                     if (distribution_SW(generator_SW) >= ACK_LOSS_PROB_SW) {
                         std::cout << "[Receiver] Sending ACK for seq=" << ack.ackNum << std::endl;
                         channel_B_to_A_SW.push_back(ack);
                     } else {
                          std::cout << "[Network] <<< ACK " << ack.ackNum << " lost B->A >>>" << std::endl;
                     }
                     cv_sender_SW.notify_one();
                 }
                receiver_expected_seq_num = (receiver_expected_seq_num + 1);

            } else {
                 std::cout << "[Receiver] Packet seq=" << received_packet.seqNum << " is unexpected (expected " << receiver_expected_seq_num << "). Discarding." << std::endl;

                 Ack_SW ack;
                 ack.ackNum = (receiver_expected_seq_num + MAX_SEQ_NUM - 1) % MAX_SEQ_NUM; // Ack last received
                 if (receiver_expected_seq_num != 0 || sender_base != 0) { // Avoid sending ACK -1 initially
                     {
                         std::lock_guard<std::mutex> lock(channel_mutex_SW);
                         if (distribution_SW(generator_SW) >= ACK_LOSS_PROB_SW) {
                             std::cout << "[Receiver] Resending ACK for last accepted seq=" << ack.ackNum << std::endl;
                             channel_B_to_A_SW.push_back(ack);
                         } else {
                              std::cout << "[Network] <<< ACK " << ack.ackNum << " lost B->A >>>" << std::endl;
                         }
                         cv_sender_SW.notify_one();
                     }
                 }
            }
        }
          std::this_thread::sleep_for(5ms);
    }
     std::cout << "[Receiver] Simulation stopped." << std::endl;
}


void monitor_SW() {
    while (!stop_simulation_SW) {
        std::this_thread::sleep_for(1s);
        if (stop_simulation_SW) break;

        std::lock_guard<std::mutex> lock_s(sender_mutex);
        std::lock_guard<std::mutex> lock_r(receiver_mutex);

        std::cout << "\n--- Monitor Tick ---" << std::endl;

        // Sender Window State
        std::cout << "Sender State:" << std::endl;
        int base = sender_base;
        int next_seq = sender_next_seq_num;
        std::string acked_str = "  Acked: [";
         for(int i = 0; i < base; ++i) acked_str += std::to_string(i) + " ";
         acked_str += "]";
         std::cout << acked_str << std::endl;


        std::string sent_not_acked_str = "  SentNotAcked: [";
        std::string allowed_not_sent_str = "  AllowedNotSent: [";
        std::string not_allowed_str = "  NotAllowed: [";

        int current = base;
        int end_window = (base + WINDOW_SIZE); // Simple non-wrapping display limit

        for (int i=0; i < MAX_SEQ_NUM; ++i){
             if(sender_buffer.count(i)){
                 sent_not_acked_str += std::to_string(i) + " ";
             } else if (i >= base && i < next_seq && i < end_window) {
                // This case might be covered by buffer check or mean acked? Refine logic if needed.
             } else if (i >= next_seq && i < end_window) {
                 allowed_not_sent_str += std::to_string(i) + " ";
             } else if (i >= end_window){
                  not_allowed_str += std::to_string(i) + " ";
             }
        }
        // Handle wrap around display if needed for accuracy

        sent_not_acked_str += "]";
        allowed_not_sent_str += "]";
        not_allowed_str += "]";

        std::cout << sent_not_acked_str << std::endl;
        std::cout << allowed_not_sent_str << std::endl;
        std::cout << not_allowed_str << std::endl;
        std::cout << "  Base=" << base << ", NextSeqNum=" << next_seq << ", WindowSize=" << WINDOW_SIZE << std::endl;


        // Receiver Window State
        std::cout << "Receiver State:" << std::endl;
        int expected_seq = receiver_expected_seq_num;
        std::string delivered_str = "  Delivered/Acked Up To: " + std::to_string((expected_seq + MAX_SEQ_NUM -1)%MAX_SEQ_NUM);
        std::cout << delivered_str << std::endl;
        std::string allowed_recv_str = "  AllowedToReceive: [" + std::to_string(expected_seq);
        allowed_recv_str += "]"; // In GBN, only expected is allowed
         std::cout << allowed_recv_str << std::endl;
        // Not allowed string could be complex, maybe omit for simplicity


        // Windows Calculation
        int advertised_window = WINDOW_SIZE; // Receiver buffer size assumed = window size here
        int outstanding_packets = 0;
         current = base;
         while(current != next_seq){
             outstanding_packets++;
             current = (current + 1) % MAX_SEQ_NUM;
             if (current == 0 && next_seq == 0) break;
             if (base > next_seq && current == next_seq) break;
         }


        int usable_window = std::max(0, advertised_window - outstanding_packets);

        std::cout << "Calculated Windows:" << std::endl;
        std::cout << "  通知窗口 (Advertised Window): " << advertised_window << std::endl;
        std::cout << "  可用窗口 (Usable Window): " << usable_window << std::endl;

        std::cout << "--- End Monitor Tick ---\n" << std::endl;
    }
     std::cout << "[Monitor] Simulation stopped." << std::endl;
}


int main_sliding_window(int argc, char* argv[]) {
    std::thread sender_thread_SW(sender_SW);
    std::thread receiver_thread_SW(receiver_SW);
    std::thread monitor_thread_SW(monitor_SW);

    sender_thread_SW.join();
    receiver_thread_SW.join();

    stop_simulation_SW = true; // Ensure monitor stops
    monitor_thread_SW.join();


    std::cout << "Sliding Window (Go-Back-N) simulation finished." << std::endl;
    return 0;
}
